#ifndef THINK_THINK_CONSOLE_OUTPUT_DRIVER_CONSOLE_H
#define THINK_THINK_CONSOLE_OUTPUT_DRIVER_CONSOLE_H

static char* think_console_output_driver_console =
	"\n"
	"// +----------------------------------------------------------------------\n"
	"// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]\n"
	"// +----------------------------------------------------------------------\n"
	"// | Copyright (c) 2006-2016 http://thinkphp.cn All rights reserved.\n"
	"// +----------------------------------------------------------------------\n"
	"// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )\n"
	"// +----------------------------------------------------------------------\n"
	"// | Author: yunwuxin <448901948@qq.com>\n"
	"// +----------------------------------------------------------------------\n"
	"\n"
	"namespace think\\console\\output\\driver;\n"
	"\n"
	"use think\\console\\Output;\n"
	"use think\\console\\output\\Formatter;\n"
	"\n"
	"class Console\n"
	"{\n"
	"\n"
	"    /** @var  Resource */\n"
	"    private $stdout;\n"
	"\n"
	"    /** @var  Formatter */\n"
	"    private $formatter;\n"
	"\n"
	"    private $terminalDimensions;\n"
	"\n"
	"    /** @var  Output */\n"
	"    private $output;\n"
	"\n"
	"    public function __construct(Output $output)\n"
	"    {\n"
	"        $this->output    = $output;\n"
	"        $this->formatter = new Formatter();\n"
	"        $this->stdout    = $this->openOutputStream();\n"
	"        $decorated       = $this->hasColorSupport($this->stdout);\n"
	"        $this->formatter->setDecorated($decorated);\n"
	"    }\n"
	"\n"
	"    public function getFormatter()\n"
	"    {\n"
	"        return $this->formatter;\n"
	"    }\n"
	"\n"
	"    public function setDecorated($decorated)\n"
	"    {\n"
	"        $this->formatter->setDecorated($decorated);\n"
	"    }\n"
	"\n"
	"    public function write($messages, $newline = false, $type = Output::OUTPUT_NORMAL, $stream = null)\n"
	"    {\n"
	"        if (Output::VERBOSITY_QUIET === $this->output->getVerbosity()) {\n"
	"            return;\n"
	"        }\n"
	"\n"
	"        $messages = (array) $messages;\n"
	"\n"
	"        foreach ($messages as $message) {\n"
	"            switch ($type) {\n"
	"                case Output::OUTPUT_NORMAL:\n"
	"                    $message = $this->formatter->format($message);\n"
	"                    break;\n"
	"                case Output::OUTPUT_RAW:\n"
	"                    break;\n"
	"                case Output::OUTPUT_PLAIN:\n"
	"                    $message = strip_tags($this->formatter->format($message));\n"
	"                    break;\n"
	"                default:\n"
	"                    throw new \\InvalidArgumentException(sprintf(\'Unknown output type given (%s)\', $type));\n"
	"            }\n"
	"\n"
	"            $this->doWrite($message, $newline, $stream);\n"
	"        }\n"
	"    }\n"
	"\n"
	"    public function renderException(\\Exception $e)\n"
	"    {\n"
	"        $stderr    = $this->openErrorStream();\n"
	"        $decorated = $this->hasColorSupport($stderr);\n"
	"        $this->formatter->setDecorated($decorated);\n"
	"\n"
	"        do {\n"
	"            $title = sprintf(\'  [%s]  \', get_class($e));\n"
	"\n"
	"            $len = $this->stringWidth($title);\n"
	"\n"
	"            $width = $this->getTerminalWidth() ? $this->getTerminalWidth() - 1 : PHP_INT_MAX;\n"
	"\n"
	"            if (defined(\'HHVM_VERSION\') && $width > 1 << 31) {\n"
	"                $width = 1 << 31;\n"
	"            }\n"
	"            $lines = [];\n"
	"            foreach (preg_split(\'/\\r?\\n/\', $e->getMessage()) as $line) {\n"
	"                foreach ($this->splitStringByWidth($line, $width - 4) as $line) {\n"
	"\n"
	"                    $lineLength = $this->stringWidth(preg_replace(\'/\\[[^m]*m/\', \'\', $line)) + 4;\n"
	"                    $lines[]    = [$line, $lineLength];\n"
	"\n"
	"                    $len = max($lineLength, $len);\n"
	"                }\n"
	"            }\n"
	"\n"
	"            $messages   = [\'\', \'\'];\n"
	"            $messages[] = $emptyLine = sprintf(\'<error>%s</error>\', str_repeat(\' \', $len));\n"
	"            $messages[] = sprintf(\'<error>%s%s</error>\', $title, str_repeat(\' \', max(0, $len - $this->stringWidth($title))));\n"
	"            foreach ($lines as $line) {\n"
	"                $messages[] = sprintf(\'<error>  %s  %s</error>\', $line[0], str_repeat(\' \', $len - $line[1]));\n"
	"            }\n"
	"            $messages[] = $emptyLine;\n"
	"            $messages[] = \'\';\n"
	"            $messages[] = \'\';\n"
	"\n"
	"            $this->write($messages, true, Output::OUTPUT_NORMAL, $stderr);\n"
	"\n"
	"            if (Output::VERBOSITY_VERBOSE <= $this->output->getVerbosity()) {\n"
	"                $this->write(\'<comment>Exception trace:</comment>\', true, Output::OUTPUT_NORMAL, $stderr);\n"
	"\n"
	"                // exception related properties\n"
	"                $trace = $e->getTrace();\n"
	"                array_unshift($trace, [\n"
	"                    \'function\' => \'\',\n"
	"                    \'file\'     => $e->getFile() !== null ? $e->getFile() : \'n/a\',\n"
	"                    \'line\'     => $e->getLine() !== null ? $e->getLine() : \'n/a\',\n"
	"                    \'args\'     => [],\n"
	"                ]);\n"
	"\n"
	"                for ($i = 0, $count = count($trace); $i < $count; ++$i) {\n"
	"                    $class    = isset($trace[$i][\'class\']) ? $trace[$i][\'class\'] : \'\';\n"
	"                    $type     = isset($trace[$i][\'type\']) ? $trace[$i][\'type\'] : \'\';\n"
	"                    $function = $trace[$i][\'function\'];\n"
	"                    $file     = isset($trace[$i][\'file\']) ? $trace[$i][\'file\'] : \'n/a\';\n"
	"                    $line     = isset($trace[$i][\'line\']) ? $trace[$i][\'line\'] : \'n/a\';\n"
	"\n"
	"                    $this->write(sprintf(\' %s%s%s() at <info>%s:%s</info>\', $class, $type, $function, $file, $line), true, Output::OUTPUT_NORMAL, $stderr);\n"
	"                }\n"
	"\n"
	"                $this->write(\'\', true, Output::OUTPUT_NORMAL, $stderr);\n"
	"                $this->write(\'\', true, Output::OUTPUT_NORMAL, $stderr);\n"
	"            }\n"
	"        } while ($e = $e->getPrevious());\n"
	"\n"
	"    }\n"
	"\n"
	"    /**\n"
	"     * 获取终端宽度\n"
	"     * @return int|null\n"
	"     */\n"
	"    protected function getTerminalWidth()\n"
	"    {\n"
	"        $dimensions = $this->getTerminalDimensions();\n"
	"\n"
	"        return $dimensions[0];\n"
	"    }\n"
	"\n"
	"    /**\n"
	"     * 获取终端高度\n"
	"     * @return int|null\n"
	"     */\n"
	"    protected function getTerminalHeight()\n"
	"    {\n"
	"        $dimensions = $this->getTerminalDimensions();\n"
	"\n"
	"        return $dimensions[1];\n"
	"    }\n"
	"\n"
	"    /**\n"
	"     * 获取当前终端的尺寸\n"
	"     * @return array\n"
	"     */\n"
	"    public function getTerminalDimensions()\n"
	"    {\n"
	"        if ($this->terminalDimensions) {\n"
	"            return $this->terminalDimensions;\n"
	"        }\n"
	"\n"
	"        if (\'\\\\\' === DS) {\n"
	"            if (preg_match(\'/^(\\d+)x\\d+ \\(\\d+x(\\d+)\\)$/\', trim(getenv(\'ANSICON\')), $matches)) {\n"
	"                return [(int) $matches[1], (int) $matches[2]];\n"
	"            }\n"
	"            if (preg_match(\'/^(\\d+)x(\\d+)$/\', $this->getMode(), $matches)) {\n"
	"                return [(int) $matches[1], (int) $matches[2]];\n"
	"            }\n"
	"        }\n"
	"\n"
	"        if ($sttyString = $this->getSttyColumns()) {\n"
	"            if (preg_match(\'/rows.(\\d+);.columns.(\\d+);/i\', $sttyString, $matches)) {\n"
	"                return [(int) $matches[2], (int) $matches[1]];\n"
	"            }\n"
	"            if (preg_match(\'/;.(\\d+).rows;.(\\d+).columns/i\', $sttyString, $matches)) {\n"
	"                return [(int) $matches[2], (int) $matches[1]];\n"
	"            }\n"
	"        }\n"
	"\n"
	"        return [null, null];\n"
	"    }\n"
	"\n"
	"    /**\n"
	"     * 获取stty列数\n"
	"     * @return string\n"
	"     */\n"
	"    private function getSttyColumns()\n"
	"    {\n"
	"        if (!function_exists(\'proc_open\')) {\n"
	"            return;\n"
	"        }\n"
	"\n"
	"        $descriptorspec = [1 => [\'pipe\', \'w\'], 2 => [\'pipe\', \'w\']];\n"
	"        $process        = proc_open(\'stty -a | grep columns\', $descriptorspec, $pipes, null, null, [\'suppress_errors\' => true]);\n"
	"        if (is_resource($process)) {\n"
	"            $info = stream_get_contents($pipes[1]);\n"
	"            fclose($pipes[1]);\n"
	"            fclose($pipes[2]);\n"
	"            proc_close($process);\n"
	"\n"
	"            return $info;\n"
	"        }\n"
	"        return;\n"
	"    }\n"
	"\n"
	"    /**\n"
	"     * 获取终端模式\n"
	"     * @return string <width>x<height> 或 null\n"
	"     */\n"
	"    private function getMode()\n"
	"    {\n"
	"        if (!function_exists(\'proc_open\')) {\n"
	"            return;\n"
	"        }\n"
	"\n"
	"        $descriptorspec = [1 => [\'pipe\', \'w\'], 2 => [\'pipe\', \'w\']];\n"
	"        $process        = proc_open(\'mode CON\', $descriptorspec, $pipes, null, null, [\'suppress_errors\' => true]);\n"
	"        if (is_resource($process)) {\n"
	"            $info = stream_get_contents($pipes[1]);\n"
	"            fclose($pipes[1]);\n"
	"            fclose($pipes[2]);\n"
	"            proc_close($process);\n"
	"\n"
	"            if (preg_match(\'/--------+\\r?\\n.+?(\\d+)\\r?\\n.+?(\\d+)\\r?\\n/\', $info, $matches)) {\n"
	"                return $matches[2] . \'x\' . $matches[1];\n"
	"            }\n"
	"        }\n"
	"        return;\n"
	"    }\n"
	"\n"
	"    private function stringWidth($string)\n"
	"    {\n"
	"        if (!function_exists(\'mb_strwidth\')) {\n"
	"            return strlen($string);\n"
	"        }\n"
	"\n"
	"        if (false === $encoding = mb_detect_encoding($string)) {\n"
	"            return strlen($string);\n"
	"        }\n"
	"\n"
	"        return mb_strwidth($string, $encoding);\n"
	"    }\n"
	"\n"
	"    private function splitStringByWidth($string, $width)\n"
	"    {\n"
	"        if (!function_exists(\'mb_strwidth\')) {\n"
	"            return str_split($string, $width);\n"
	"        }\n"
	"\n"
	"        if (false === $encoding = mb_detect_encoding($string)) {\n"
	"            return str_split($string, $width);\n"
	"        }\n"
	"\n"
	"        $utf8String = mb_convert_encoding($string, \'utf8\', $encoding);\n"
	"        $lines      = [];\n"
	"        $line       = \'\';\n"
	"        foreach (preg_split(\'//u\', $utf8String) as $char) {\n"
	"            if (mb_strwidth($line . $char, \'utf8\') <= $width) {\n"
	"                $line .= $char;\n"
	"                continue;\n"
	"            }\n"
	"            $lines[] = str_pad($line, $width);\n"
	"            $line    = $char;\n"
	"        }\n"
	"        if (strlen($line)) {\n"
	"            $lines[] = count($lines) ? str_pad($line, $width) : $line;\n"
	"        }\n"
	"\n"
	"        mb_convert_variables($encoding, \'utf8\', $lines);\n"
	"\n"
	"        return $lines;\n"
	"    }\n"
	"\n"
	"    private function isRunningOS400()\n"
	"    {\n"
	"        $checks = [\n"
	"            function_exists(\'php_uname\') ? php_uname(\'s\') : \'\',\n"
	"            getenv(\'OSTYPE\'),\n"
	"            PHP_OS,\n"
	"        ];\n"
	"        return false !== stripos(implode(\';\', $checks), \'OS400\');\n"
	"    }\n"
	"\n"
	"    /**\n"
	"     * 当前环境是否支持写入控制台输出到stdout.\n"
	"     *\n"
	"     * @return bool\n"
	"     */\n"
	"    protected function hasStdoutSupport()\n"
	"    {\n"
	"        return false === $this->isRunningOS400();\n"
	"    }\n"
	"\n"
	"    /**\n"
	"     * 当前环境是否支持写入控制台输出到stderr.\n"
	"     *\n"
	"     * @return bool\n"
	"     */\n"
	"    protected function hasStderrSupport()\n"
	"    {\n"
	"        return false === $this->isRunningOS400();\n"
	"    }\n"
	"\n"
	"    /**\n"
	"     * @return resource\n"
	"     */\n"
	"    private function openOutputStream()\n"
	"    {\n"
	"        if (!$this->hasStdoutSupport()) {\n"
	"            return fopen(\'php://output\', \'w\');\n"
	"        }\n"
	"        return @fopen(\'php://stdout\', \'w\') ?: fopen(\'php://output\', \'w\');\n"
	"    }\n"
	"\n"
	"    /**\n"
	"     * @return resource\n"
	"     */\n"
	"    private function openErrorStream()\n"
	"    {\n"
	"        return fopen($this->hasStderrSupport() ? \'php://stderr\' : \'php://output\', \'w\');\n"
	"    }\n"
	"\n"
	"    /**\n"
	"     * 将消息写入到输出。\n"
	"     * @param string $message 消息\n"
	"     * @param bool   $newline 是否另起一行\n"
	"     * @param null   $stream\n"
	"     */\n"
	"    protected function doWrite($message, $newline, $stream = null)\n"
	"    {\n"
	"        if (null === $stream) {\n"
	"            $stream = $this->stdout;\n"
	"        }\n"
	"        if (false === @fwrite($stream, $message . ($newline ? PHP_EOL : \'\'))) {\n"
	"            throw new \\RuntimeException(\'Unable to write output.\');\n"
	"        }\n"
	"\n"
	"        fflush($stream);\n"
	"    }\n"
	"\n"
	"    /**\n"
	"     * 是否支持着色\n"
	"     * @param $stream\n"
	"     * @return bool\n"
	"     */\n"
	"    protected function hasColorSupport($stream)\n"
	"    {\n"
	"        if (DIRECTORY_SEPARATOR === \'\\\\\') {\n"
	"            return\n"
	"            \'10.0.10586\' === PHP_WINDOWS_VERSION_MAJOR . \'.\' . PHP_WINDOWS_VERSION_MINOR . \'.\' . PHP_WINDOWS_VERSION_BUILD\n"
	"            || false !== getenv(\'ANSICON\')\n"
	"            || \'ON\' === getenv(\'ConEmuANSI\')\n"
	"            || \'xterm\' === getenv(\'TERM\');\n"
	"        }\n"
	"\n"
	"        return function_exists(\'posix_isatty\') && @posix_isatty($stream);\n"
	"    }\n"
	"\n"
	"}\n"
	"\n"
;
#endif